using System;
using System.Collections.Generic;
using System.Text;

namespace Fuzzy
{
    /// <summary>
    /// An abstract class representing a fuzzy set.
    /// </summary>
    public abstract class FuzzySet
    {
        protected string name;
        
        /// <summary>
        /// Gets or sets the name of the fuzzy variable.
        /// </summary>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        protected FuzzyLinguisticVariable fuzzyLinguisticVariable;

        /// <summary>
        /// Gets or sets the fuzzy linguistic variable where the fuzzy set belongs to.
        /// </summary>
        public FuzzyLinguisticVariable FuzzyLinguisticVariable
        {
            get { return fuzzyLinguisticVariable; }
            set { fuzzyLinguisticVariable = value; }
        }

        /// <summary>
        /// Creates a fuzzy set.
        /// </summary>
        /// <param name="fuzzyLinguisticVariable">The linguistic variable where the set belongs to.</param>
        public FuzzySet(FuzzyLinguisticVariable fuzzyLinguisticVariable)
        {
            this.name = "";
            this.fuzzyLinguisticVariable = fuzzyLinguisticVariable;
        }

        /// <summary>
        /// Creates a fuzzy set.
        /// </summary>
        /// <param name="fuzzyLinguisticVariable">The linguistic variable where the set belongs to.</param>
        /// <param name="name">The name of the fuzzy set.</param>
        public FuzzySet(FuzzyLinguisticVariable fuzzyLinguisticVariable, string name)
        {
            this.name = name;
            this.fuzzyLinguisticVariable = fuzzyLinguisticVariable;
        }

        /// <summary>
        /// The membership function of the fuzzy set.
        /// </summary>
        /// <param name="x">The number of which membership we are interested in.</param>
        /// <returns>The membership of x.</returns>
        public abstract double Membership(double x);

        /// <summary>
        /// The alpha cut of the fuzzy set.
        /// </summary>
        /// <param name="alpha">The alpha value to which the alpha cut belongs.</param>
        /// <returns>An array consisting two-element double arrays with intervals.</returns>
        public abstract double[][] AlphaCut(double alpha);

        /// <summary>
        /// The strict alpha cut of the fuzzy set.
        /// </summary>
        /// <param name="alpha">The alpha value to which the strict alpha cut belongs.</param>
        /// <returns>An array consisting two-element double arrays with intervals.</returns>
        public abstract double[][] StrictAlphaCut(double alpha);

        /// <summary>
        /// The core of the fuzzy set. (Strict alpha cut, where alpha = 0.)
        /// </summary>
        /// <returns>An array consisting two-element double arrays with intervals.</returns>
        public virtual double[][] Core()
        {
            return StrictAlphaCut(0);
        }

        /// <summary>
        /// The support of the fuzzy set. (Alpha cut, where alpha = 1.)
        /// </summary>
        /// <returns>An array consisting two-element double arrays with intervals.</returns>
        public virtual double[][] Support()
        {
            return AlphaCut(1);
        }

        /// <summary>
        /// Computes the union of fuzzy sets.
        /// </summary>
        /// <param name="fuzzySet">The other operand of union.</param>
        /// <returns>The union of the fuzzy sets.</returns>
        public virtual FuzzySet Union(FuzzySet fuzzySet)
        {
            return Union(fuzzySet, true);
        }

        /// <summary>
        /// Computes the intersection of fuzzy sets.
        /// </summary>
        /// <param name="fuzzySet">The other operand of union.</param>
        /// <returns>The union of the fuzzy sets.</returns>
        public virtual FuzzySet Intersection(FuzzySet fuzzySet)
        {
            return Intersection(fuzzySet, true);
        }

        internal abstract FuzzySet Union(FuzzySet fuzzySet, bool mayRedirect);
        internal abstract FuzzySet Intersection(FuzzySet fuzzySet, bool mayRedirect);

        /// <summary>
        /// Computes the complement of the fuzzy set.
        /// </summary>
        /// <returns>The complement of the fuzzy set.</returns>
        public abstract FuzzySet Complement();

        /// <summary>
        /// Returns the defuzzified value of the fuzzy set. (The defuzzification method is set in FuzzyUniverse.)
        /// </summary>
        /// <returns>The complement of the fuzzy set.</returns>
        public virtual double GetDefuzzifiedValue()
        {
            return FuzzyUniverse.Defuzzification.DefuzzifiedValue(this);
        }

        /// <summary>
        /// Determines the supreme of the membership value of the fuzzy set. 
        /// </summary>
        /// <returns>The supreme of the membership value of the fuzzy set.</returns>
        public abstract double Sup();
        
    }
}
